package com.tiemei.demo;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * java正则例子
 * 加个图形化工具，贴一段字符串进去，再贴一个正则进去，立即看到效果：
 * http://code.google.com/p/qre/
 * 
 * @author tiemei
 * @date Mar 10, 2013
 */
public class RegexDemo {
	public static void main(String args[]) {

		firstDemo();
		System.out.println("-----------------");
		whatIsGroup();
		System.out.println("-----------------");
		testStart();
		System.out.println("-----------------");
		testAppend();
		
		/*
		 * 匹配'\'而不要被正则里解释成转义字符，需要用四个反斜杠
		 */
		Pattern p = Pattern.compile("(\\||\\\\)");
		Matcher m = p.matcher("|nihao\\");
		System.out.println(m.replaceAll("-"));
		
		/*
		 * '['单独用会报错，要匹配[必须要加转义
		 * ｛ ｛ | 
		 */
		p = Pattern.compile("\\[\\{\\(=!");
		m = p.matcher("[nihao");
		System.out.println(m.replaceAll("-"));
		
		/**
		 *  /b表示单词的边界
		 */
		p = Pattern.compile("\\\\d");
		m = p.matcher("hello\b!=\\d");
		System.out.println(m.replaceAll("-"));
		
		
	}

	/**
	 * 找到字符串中已'a'开头的单词
	 */
	public static void firstDemo() {
		String target = "A Matcher examines the results of applying a pattern.】";
		String regex = "\\ba\\w*\\b";
		/*
		 *  1 create Pattern obj
		 *  1.1 可用flags
		 *  static Pattern compile(String regex, int flags) 
		 *  UNIX_LINES : 这个主要处理UNIX和其他的操作系统在行结束符不一样的问题，UNIX使用\n代表一行的终止，而Windows 则使用了\r\n,\n,\r,\u2028或者\u0085作为一行的结束符
		 *  CASE_INSENSITIVE : 忽略大小写
		 *  COMMENTS ： 允许使用注释，Pattern p =Pattern.compile("A    #matches uppercase US-ASCII char code 65",Pattern.COMMENTS);
		 *  MULTILINE ： 匹配多行
		 *  DOTALL ： 是否匹配一行的终止符 Pattern p = Pattern.compile(".", Pattern.DOTALL);匹配的'Test\n'字符数为5
		 *  UNICODE_CASE ： 处理UNICODE字符集，使用这个选项会降低效率 
		 *  CANON_EQ ： 匹配一个字符在各种场景下的编码，例如a可以匹配+00E0和U+0061U+0300 
		 *  
		 *  1.2 组合使用
		 *  attern p =  
         * Pattern.compile("t # a compound flag example",Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE|  
		 * Pattern.COMMENT); 
		 * 
		 * 1.3 注意点
		 *  注意转义字符，例如数字的匹配模式是  "\\d" 非 "\d"
		 *  如果regex本身形式是错误的，compile方法会抛出java.util.regex.PatternSyntaxException异常
		 */
		Pattern p = Pattern.compile(regex); 
		
		/*
		 * get matcher obj
		 * 
		 * public Matcher matcher(CharSequence input)
		 * 1. CharBuffer, Segment, String, StringBuffer, StringBuilder 都实现了这个接口，所以参数可以是这些中的任一种类型了
		 * 2. 判断是否设置了某个选项：
		 * int flgs = myPattern.flags();  
         * boolean isUsingCommentFlag =( Pattern.COMMENTS == (Pattern.COMMENTS & flgs)) ; 
         * 
         * 3. public static boolean matches (String regex,CharSequence input) 
         * 实际是下面的简化版本：
         * Pattern p = Pattern.compile(regex);  
		 * Matcher m = p.matcher(candidate);  
         * m.matches()
         * 
         * 4. split方法增强版本 
         * 类似String的方式 split,pattern提供了同样的方式，支持正则
         * Pattern p = new Pattern.compile(",|and");  
		 * String fruits[] = p.split("apple,banana and orange");  
		 * 
		 * public String[] split(CharSequence input, int limit) 重载，增加了limit参数
		 * limit = 0 同没有时
		 * limit > 0 只要前limit个
		 * limit < -1 尽可能划分
		 * Pattern p = Pattern.compile(",");  
		 * String temp[] = p.split("Hello,Dolly,", -1);  
		 * //temp[]={"Hello","Dolly",""}  
		 */
		Matcher m = p.matcher(target); 
		
		
		String val = null;
		while (m.find()) {
			val = m.group();
			System.out.println("MATCH: " + val);
		}
	}
	
	/**
	 * 讲解mathcer中group的概念
	 */
	public static void whatIsGroup () {
		String regex = "\\w(\\d\\d)(\\w+)";  
        String candidate = "x99SuperJava";  
          
        Pattern p = Pattern.compile(regex);  
        Matcher matcher = p.matcher(candidate);  
        if(matcher.find()){  
            int gc = matcher.groupCount();  
            for(int i = 0; i <= gc; i++)  
                System.out.println("group " + i + " :" + matcher.group(i));  
        }  
		
	}

	/**
	 * Mathcer类中的方式：
	 * 1. public Pattern pattern() 返回对应的pattern obj
	 * 2. public Matcher reset()  这个方法将Matcher的状态重新设置为最初的状态
	 * 3. public Matcher reset(CharSequence input)  和重新创建一个Matcher一样，只是这样可以重用之前的matcher obj
	 * 
	 * 4. public int start()  返回Matcher所匹配的字符串在整个字符串的的开始下标
	 *  public int start(int group) 返回指定group的index
	 *	public int end()  匹配到的结尾index
	 *  public int end(int group) 
	 *  
	 * 5. public String group()   匹配到的内容
	 * group(int) gourpCount() 
	 * 
	 * 6. public boolean matches() 将整个区域与模式匹配。这个要求整个输入字符串都要和正则表达式匹配
	 *  public boolean find()  find只是超找匹配字符串，不一定是整个模式匹配
	 *  public boolean find(int start)  从指定index开始查找
	 *  public boolean lookingAt() 基本上是matches更松约束的一个方法，尝试将从区域开头开始的输入序列与该模式匹配
	 *  
	 *  7. public Matcher appendReplacement (StringBuffer sb, String replacement)   替换，进行多次find时，mathcer也能成功找到变化的每次start index
	 *   
	 */
	
	/**
	 * 验证start()方法
	 */
	public static void testStart() {
		String candidateString = "My name is Bond. James Bond."; // 有连个bond，找到它们再字符串中的index
		Pattern p = Pattern.compile("Bond");
		Matcher m =  p.matcher(candidateString);
		m.find();
		System.out.println(m.start());
		System.out.println(m.end());
		m.find();
		System.out.println(m.start());
		System.out.println(m.end());
	}
	
	
	/**
	 * 验证  appendReplacement appendTail
	 */
	public static void testAppend() {
		StringBuffer sb = new StringBuffer();  
		String replacement = "Smith";  
		Pattern pattern = Pattern.compile("Bond");  
		Matcher matcher =pattern.matcher("My name is Bond. James Bond. I would like a martini.");  
		while(matcher.find()){  
		  matcher.appendReplacement(sb,replacement);//结果是My name is Smith. James Smith  
		} 
		System.out.println(sb.toString());
		matcher.appendTail(sb);  // 加上这句结果变成： My name is Smith. James Smith. I would like a martini. 
		System.out.println(sb.toString());
		
		/*
		 * 全部替换更为简单的方式： public String replaceAll(String replacement) 
		 * 顺便加个方法  public String replaceFirst(String replacement) 
		 */
	}
	
	
	
	
	
}
